#include "Buffer.h"
#include <algorithm>
#include <error.h>
#include <unistd.h>
#include <sys/uio.h>
#include "util.h"

const char Buffer::kCRLF[] = "\r\n";
const char Buffer::kOneTwo[] = "12";

const char* Buffer::findCRLF() const {
    const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2);
    return crlf == beginWrite() ? NULL : crlf;
}
const char* Buffer::find12() const {
    const char* crlf = std::search(peek(), beginWrite(), kOneTwo, kOneTwo+2);
    return crlf == beginWrite() ? NULL : crlf;
}

void Buffer::retrieve(size_t len) {
    // assert(len <= readableBytes());
    if (len < readableBytes()) readIndex += len;
    else retrieveAll();
}

void Buffer::append(const char* data, size_t len) {
    // 检测可写空间够不够
    if ( writableBytes() < len ) {
        if ( writableBytes() + prependableBytes() < len ) {
            buffer_.resize( writeIndex + len );
        }
        else {
            size_t readable = readableBytes();
            std::copy( begin() + readIndex, begin() + writeIndex, begin() );
            readIndex = 0;
            writeIndex = readIndex + readable;
            // assert(readable == readableBytes());
        }
    }
    // assert(writableBytes() >= len);

    std::copy(data, data+len, begin()+writeIndex);

    // assert(len <= writableBytes());
    writeIndex += len;
}

ssize_t Buffer::readFd(int fd, int* savedErrno) {
    while (true) {
        char extrabuf[65536];
        struct iovec vec[2];
        const size_t writable = writableBytes();    // buffer_中可写字节

        vec[0].iov_base = begin() + writeIndex;   // buffer_中可写起始位置
        vec[0].iov_len = writable;
        vec[1].iov_base = extrabuf;                 // extrabuf中可写起始位置
        vec[1].iov_len = sizeof(extrabuf);

        const int iovcnt = (writable < sizeof(extrabuf)) ? 2 : 1;

        const ssize_t n = readv(fd, vec, iovcnt);
        if ( n < 0 ) {
            *savedErrno = errno;
            // break;
            if ( errno == EINTR) {
                continue;
            } 
            else {
                // EAGAIN或出错时退出
                return n;
            }
        }
        // n == 0 对方关闭连接
        else if ( n == 0 ) {
            return n;
        }
        // n > 0 读取到数据
        else if ( static_cast<size_t>(n) <= writable ) {
            writeIndex += n;
        }
        else {
            writeIndex = buffer_.size();
            append(extrabuf, n - writable);
        }
    }
}
